#ifndef SEM_V2_HPP
#define SEM_V2_HPP

#include <boost/system/error_code.hpp>
#include<iostream>
#include <memory>
#include<string>
#include<sys/types.h>
#include<vector>
#include<sys/ipc.h>
#include<sys/sem.h>
#include<unistd.h>

// //简单的建造者模式

// //仅关注使用和删除
// class Semaphore
// {
// 
// private:
//     int _semid;
// };

// //关注建造
// class SemaphoreBuilder
// {
// public:
//     

//     SemaphoreBuilder()
//     {}

//     ~SemaphoreBuilder()
//     {}

//     SemaphoreBuilder &SetVal(int val)
//     {
//         _val = val;
//         return *this;
//     } 

//     std::shared_ptr<Semaphore> Build(int flag,const int nsem = defaultnsem)
//     {
//         std::cout << "Build Semaphore" << std::endl;
//         
//         
//     }

// private:
//     int _val;  //所有信号量的初始值
// };


////////////////////////////具体的建造者设计模式代码架构//////////////////////////////////////

const std::string PATH_NAME = "/tmp";
const int PROJ_ID = 0x77;
const int defaultnsem = 1;
const int Sem_P = -1;
const int Sem_V = 1;
#define GET_SEM (IPC_CREAT)
#define BUILD_SEM (IPC_CREAT | IPC_EXCL)

//产品类,关注使用和删除
class Semaphore
{
public:
    Semaphore(int semid):_semid(semid) {}

    int ID() {return _semid;}
private:
    void PV(int who,int PorV)
    {
        struct sembuf sb;
        sb.sem_num = who;          //信号量编号，从0开始
        sb.sem_op = PorV;        //S + sem_buf.sem_op
        sb.sem_flg = SEM_UNDO;   //不关心
        int n = ::semop(_semid, &sb, 1);
        (void)n;
    }
public:
    ~Semaphore()
    {
        if(_semid >= 0)
        {
            int n = ::semctl(_semid,0,IPC_RMID);
            if(n < 0)
            {
                std::cerr << "semctl IPC_RMID Error" << std::endl;
            }
            std::cout << "Semphore " << _semid << " removed" << std::endl;
        }
    }

    void P(int who) {PV(who,Sem_P);}

    void V(int who) {PV(who,Sem_V);}

private:
    int _semid;
};

//建造者接口，虚基类
class SemaphoreBuilder
{
public:
    virtual ~SemaphoreBuilder() = default;
    virtual void BuildKey() = 0;
    virtual void SetPermission(int perm) = 0;
    virtual void SetSemNum(int num) = 0;
    virtual void SetInitVal(std::vector<int> initval) = 0;
    virtual void Build(int flag) = 0;
    virtual void InitSem() = 0;
    virtual std::shared_ptr<Semaphore> GetSem() = 0;
private:
};

//具体建造者，实现
class ConcreteSemphoreBuilder:public SemaphoreBuilder
{
public:
    std::string IntoHex(key_t key)
    {
        char buf[64];
        snprintf(buf,sizeof(buf),"0x%x",key);
        return std::string(buf);
    }

    ConcreteSemphoreBuilder() {}
    virtual void BuildKey() override
    {
        //1.创建键值
        _key = ::ftok(PATH_NAME.c_str(),PROJ_ID);
        if(_key < 0)
        {
            std::cerr << "Got Key Error" << std::endl;
            exit(1);
        }
        std::cout << "Got Key" << IntoHex(_key) << std::endl;
    }

    virtual void SetPermission(int perm) override {_perm = perm;}

    virtual void SetSemNum(int num) override {_num = num;}

    virtual void SetInitVal(std::vector<int> initval) override {_initVal = initval;}

    virtual void Build(int flag) override 
    {
        //2.创建信号集
        int semid = ::semget(_key,_num,flag | _perm);
        if(semid < 0)
        {
            std::cerr << "Create Sem Error" << std::endl;
            exit(2);

        }
        // //3.初始化
        // if(flag == BUILD_SEM)
        //     Init(semid,0);

        _sem = std::make_shared<Semaphore>(semid);
    }

    virtual void InitSem() override
    {
        if(_num > 0 && _initVal.size() == _num)
        {
            for(int i = 0;i < _num;i++)
            {
                if(!Init(_sem->ID(),i,_initVal[i]))
                {
                    std::cerr << "Init Error" << std::endl;
                    exit(3);
                }
            }
        }
    }
    virtual std::shared_ptr<Semaphore> GetSem() override {return _sem;}
private:
    bool Init(int semid,int num,int _val)
    {
        // 3. 初始化信号量
        union semun // 该联合体系统不提供，需要我们自己定义
        {
            int val;               /* Value for SETVAL */
            struct semid_ds *buf;  /* Buffer for IPC_STAT, IPC_SET */
            unsigned short *array; /* Array for GETALL, SETALL */
            struct seminfo *__buf; /* Buffer for IPC_INFO
                                        (Linux-specific) */
        } un;

        un.val = _val; // 设置为初始值

        int n = ::semctl(semid, num, SETVAL, un);
        if (n < 0) return false;
        return true;
    }
private:
    key_t _key;                         //信号量集合的键值
    int _perm;                         //权限
    int _num;                          //信号量集合的个数
    std::vector<int> _initVal;         //初始值
    std::shared_ptr<Semaphore> _sem; //创建的信号集产品
};

//指挥者
class Director
{
public:
    Director() {}

    void Construct(std::shared_ptr<SemaphoreBuilder> builder,int flag ,int perm = 0666,int num = defaultnsem,std::vector<int> initval = {1})
    {
        builder->BuildKey();
        builder->SetPermission(perm);
        builder->SetInitVal(initval);
        builder->SetSemNum(num);
        builder->Build(flag);
        if(flag == BUILD_SEM)
            builder->InitSem();
    }

private:
};

#endif